package com.atung.parking.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.atung.parking.config.auth.AuthUserMangerContext;
import com.atung.parking.config.result.ApiResult;
import com.atung.parking.config.result.PageInfoResponse;
import com.atung.parking.config.utils.AddressLocationUtil;
import com.atung.parking.config.utils.DistanceUtil;
import com.atung.parking.config.utils.ParkingPointOperations;
import com.atung.parking.controller.DateConvertUtil;
import com.atung.parking.dto.LocationEntity;
import com.atung.parking.entity.BusApprovalRecord;
import com.atung.parking.entity.BusParkingIot;
import com.atung.parking.entity.BusSuperUser;
import com.atung.parking.enums.AdminType;
import com.atung.parking.enums.ApprovalModelType;
import com.atung.parking.enums.ExportType;
import com.atung.parking.enums.ParkingIotApprovalState;
import com.atung.parking.export.ParkingIotExportVO;
import com.atung.parking.export.PublicExportUtil;
import com.atung.parking.mapper.BusApprovalRecordMapper;
import com.atung.parking.mapper.BusParkingIotMapper;
import com.atung.parking.mapper.BusParkingIotPackageMapper;
import com.atung.parking.mapper.BusSuperUserMapper;
import com.atung.parking.mapstruct.ParkingIotConverter;
import com.atung.parking.mapstruct.ParkingIotPackageConverter;
import com.atung.parking.request.ApprovalParkingIotRequest;
import com.atung.parking.request.query.AppQueryParkingIotRequest;
import com.atung.parking.request.query.QueryParkingIotRequest;
import com.atung.parking.request.save.SaveOrUpdateParkingIotRequest;
import com.atung.parking.response.page.AppParkingIotPackageResponse;
import com.atung.parking.response.page.AppParkingIotResponse;
import com.atung.parking.response.page.ApprovalRecordResponse;
import com.atung.parking.response.page.HardwareVendorResponse;
import com.atung.parking.service.ParkingIotService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.val;
import org.apache.commons.lang3.time.FastDateFormat;
import org.springframework.beans.BeanUtils;
import org.springframework.data.geo.Point;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author Administrator
 */
@Service
public class ParkingIotServiceImpl implements ParkingIotService {

    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private BusParkingIotMapper busParkingIotMapper;
    @Resource
    private BusSuperUserMapper busSuperUserMapper;
    @Resource
    private BusApprovalRecordMapper busApprovalRecordMapper;
    @Resource
    private ParkingIotConverter parkingIotConverter;
    @Resource
    private PublicExportUtil publicExportUtil;
    @Resource
    private ParkingPointOperations parkingPointOperations;


    @Override
    public ApiResult saveParkingIotService(SaveOrUpdateParkingIotRequest request) {
        AdminType roleType = AuthUserMangerContext.getAuthUserEntity().getRoleType();
        //超级管理员
        if (roleType.equals(AdminType.SUPERADMIN)) {
            if (Objects.isNull(request.getSuperUserId())) {
                return ApiResult.fail("客户编号不能为空");
            }
        }
        if (roleType.equals(AdminType.ADMIN)) {
            request.setSuperUserId(AuthUserMangerContext.getUserId());
        }
        if (Objects.isNull(request.getId())) {
            return this.save(request);
        }
        return this.update(request);
    }

    @Transactional
    public ApiResult save(SaveOrUpdateParkingIotRequest saveOrUpdateParkingIotRequest) {
        //校验用户是存存在
        BusSuperUser busSuperUser = busSuperUserMapper.selectById(saveOrUpdateParkingIotRequest.getSuperUserId());
        if (Objects.isNull(busSuperUser)) {
            return ApiResult.fail("客户不存在");
        }
        String[] location = AddressLocationUtil.getLonAndLatByAddress(saveOrUpdateParkingIotRequest.getAddress()
                + saveOrUpdateParkingIotRequest.getDetailedAddress()).split(",");
        BusParkingIot busParkingIot = new BusParkingIot();
        if (location.length > 1) {
            busParkingIot.setLatitude(location[0]);
            busParkingIot.setLongitude(location[1]);
        }
        BeanUtils.copyProperties(saveOrUpdateParkingIotRequest, busParkingIot);
        busParkingIot.setApprovalStatus(ParkingIotApprovalState.PENDING.getCode());
        busParkingIot.setRatePerHour(new BigDecimal(saveOrUpdateParkingIotRequest.getRatePerHour()));
        busParkingIotMapper.insert(busParkingIot);
        if (Objects.nonNull(busParkingIot.getLatitude()) &&
                Objects.nonNull(busParkingIot.getLongitude())) {
            Point point = new Point(Double.valueOf(busParkingIot.getLatitude()), Double.valueOf(busParkingIot.getLongitude()));
            stringRedisTemplate.opsForGeo().add(ParkingPointOperations.redisGeoCommandsKey, point, busParkingIot.getId().toString());

        }


        BusApprovalRecord busApprovalRecord = new BusApprovalRecord();
        busApprovalRecord.setApprovalType("创建停车场");
        busApprovalRecord.setModelType(ApprovalModelType.PARKING_IOT.name());
        busApprovalRecord.setModelId(busParkingIot.getId());
        this.saveApprovalRecord(busApprovalRecord);
        return ApiResult.ok();
    }

    @Transactional
    public ApiResult update(SaveOrUpdateParkingIotRequest saveOrUpdateParkingIotRequest) {
        BusParkingIot busParkingIot = busParkingIotMapper.selectById(saveOrUpdateParkingIotRequest.getId());

        if (Objects.isNull(busParkingIot) || !
                busParkingIot.getSuperUserId()
                        .equals(saveOrUpdateParkingIotRequest.getSuperUserId())) {
            return ApiResult.fail("数据不存在");
        }
        String[] location = AddressLocationUtil.getLonAndLatByAddress(saveOrUpdateParkingIotRequest.getAddress()
                + saveOrUpdateParkingIotRequest.getDetailedAddress()).split(",");
        if (location.length > 1) {
            busParkingIot.setLatitude(location[0]);
            busParkingIot.setLongitude(location[1]);
        }
        if (Objects.nonNull(busParkingIot.getLatitude()) &&
                Objects.nonNull(busParkingIot.getLongitude())) {
            Point point = new Point(Double.valueOf(busParkingIot.getLatitude()), Double.valueOf(busParkingIot.getLongitude()));
            stringRedisTemplate.opsForGeo().add(ParkingPointOperations.redisGeoCommandsKey, point, busParkingIot.getId().toString());

        }
        BeanUtils.copyProperties(saveOrUpdateParkingIotRequest, busParkingIot);
        busParkingIot.setApprovalStatus(ParkingIotApprovalState.PENDING.getCode());
        busParkingIotMapper.updateById(busParkingIot);
        BusApprovalRecord busApprovalRecord = new BusApprovalRecord();
        busApprovalRecord.setApprovalType("修改停车场");
        busApprovalRecord.setModelType(ApprovalModelType.PARKING_IOT.name());
        busApprovalRecord.setModelId(busParkingIot.getId());
        this.saveApprovalRecord(busApprovalRecord);
        return ApiResult.ok();
    }

    public void saveApprovalRecord(BusApprovalRecord busApprovalRecord) {
        busApprovalRecordMapper.insert(busApprovalRecord);
    }

    @Transactional
    @Override
    public ApiResult approvalParkingIotService(ApprovalParkingIotRequest request) {
        BusParkingIot busParkingIot = busParkingIotMapper.selectById(request.getId());
        if (Objects.isNull(busParkingIot)) {
            return ApiResult.fail("数据不存在");
        }
        BusApprovalRecord busApprovalRecord = new BusApprovalRecord();
        busApprovalRecord.setModelId(request.getId());
        busApprovalRecord.setModelType(ApprovalModelType.PARKING_IOT.name());
        ParkingIotApprovalState approvalState = request.getApprovalState();
        if (ParkingIotApprovalState.APPROVED.equals(approvalState)) {
            //审核不通过
            busApprovalRecord.setApprovalType("审核通过");
            busParkingIot.setApprovalStatus(ParkingIotApprovalState.APPROVED.getCode());
        } else if ((ParkingIotApprovalState.REJECTED.equals(approvalState))) {
            busApprovalRecord.setApprovalType("审核未通过");
            busParkingIot.setApprovalStatus(ParkingIotApprovalState.REJECTED.getCode());
        } else {
            return ApiResult.ok();
        }
        busParkingIotMapper.updateById(busParkingIot);
        saveApprovalRecord(busApprovalRecord);
        return ApiResult.ok();
    }

    @Override
    public PageInfoResponse<BusParkingIot> queryParkingIotListService(QueryParkingIotRequest request) {
        QueryWrapper<BusParkingIot> queryWrapper = createQueryWrapper(request);
        Page<BusParkingIot> page = new Page<>(request.getPageNum(), request.getPageSize());
        Page<BusParkingIot> busParkingIotPage = busParkingIotMapper.selectPage(page, queryWrapper);
        PageInfoResponse<BusParkingIot> pageResponse = new PageInfoResponse<>();
        pageResponse.setData(busParkingIotPage.getRecords());
        pageResponse.setTotal(busParkingIotPage.getTotal());
        return pageResponse;
    }

    @Override
    public List<BusParkingIot> querySimpleParkingIotListService() {
        QueryWrapper<BusParkingIot> queryWrapper = new QueryWrapper<>();
        AdminType roleType = AuthUserMangerContext.getAuthUserEntity().getRoleType();
        if (!roleType.equals(AdminType.SUPERADMIN)) {
            //管理员需要判断是否为自己车场
            queryWrapper.eq("super_user_id", AuthUserMangerContext.getUserId());
        }
        queryWrapper.eq("approval_status", ParkingIotApprovalState.APPROVED.getCode());
        return busParkingIotMapper.selectList(queryWrapper);
    }

    @Override
    public ApiResult<List<AppParkingIotResponse>>  appQueryByParkingName(AppQueryParkingIotRequest appQueryParkingIotRequest) {
        //根据经纬度排序

        //根据名称获取车场列表
        QueryWrapper<BusParkingIot> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("approval_status", ParkingIotApprovalState.APPROVED.getCode());
        queryWrapper.like("name", appQueryParkingIotRequest.getName());
        List<BusParkingIot> busParkingIots = busParkingIotMapper.selectList(queryWrapper);

        List<LocationEntity> locationEntities = parkingPointOperations.queryAllParkingIds(appQueryParkingIotRequest.getLat(), appQueryParkingIotRequest.getLon());


        Map<Long, LocationEntity> locationMap = locationEntities.stream()
                .collect(Collectors.toMap(LocationEntity::getId, entity -> entity, (existing, replacement) -> existing));

        // 匹配并排序
        List<BusParkingIot> sortedBusParkingIots = busParkingIots.stream()
                .filter(busParkingIot -> locationMap.containsKey(busParkingIot.getId()))
                .sorted(Comparator.comparingInt(busParkingIot -> locationEntities.indexOf(locationMap.get(busParkingIot.getId()))))
                .collect(Collectors.toList());

        List<AppParkingIotResponse> collect = sortedBusParkingIots.stream().map(item -> {
            AppParkingIotResponse appParkingIotResponse = new AppParkingIotResponse();
            BeanUtils.copyProperties(item, appParkingIotResponse);
            return appParkingIotResponse;
        }).collect(Collectors.toList());
        return ApiResult.ok(collect);

    }




    @Override
    public List<HardwareVendorResponse> queryParkingIotHardwareVendorList() {
        QueryWrapper<BusParkingIot> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("approval_status", ParkingIotApprovalState.APPROVED.getCode());
        queryWrapper.groupBy("hardware_vendor");
        queryWrapper.orderByDesc("creator_time");
        List<BusParkingIot> busParkingIotList = busParkingIotMapper.selectList(queryWrapper);

        return busParkingIotList.stream().map(item->{
          return   HardwareVendorResponse.builder().value(item.getId().toString()).name(item.getHardwareVendor()).build();
        }).collect(Collectors.toList());
    }

    @Override
    public List<ApprovalRecordResponse> queryApprovalParkingIotList(Long id) {
        QueryWrapper<BusApprovalRecord> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("model_id", id);
        queryWrapper.eq("model_type", ApprovalModelType.PARKING_IOT.name());
        List<BusApprovalRecord> approvalRecords = busApprovalRecordMapper.selectList(queryWrapper);
        return approvalRecords.stream().map(parkingIotConverter::toApprovalResponse).collect(Collectors.toList());
    }

    @Override
    public void exportParkingIotService(QueryParkingIotRequest request, HttpServletResponse httpServletResponse) {
        QueryWrapper<BusParkingIot> queryWrapper = createQueryWrapper(request);
        List<BusParkingIot> busParkingIotFranchises = busParkingIotMapper.selectList(queryWrapper);
        List<ParkingIotExportVO> collect = busParkingIotFranchises.stream().map(item -> {
            ParkingIotExportVO parkingIotExportVO = parkingIotConverter.toExportVo(item);
            String description = ParkingIotApprovalState.getDescriptionByCode(item.getApprovalStatus());
            //格式状态
            parkingIotExportVO.setApprovalStatus(description);
            //获取客户信息
            //收费标准
            parkingIotExportVO.setRatePerHour(item.getRatePerHour() + "(元)/小时");
            FastDateFormat formatter = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss");
            // 格式化日期时间
            try {
                String formattedDate = formatter.format(Long.valueOf(item.getCreatorTime()));
                parkingIotExportVO.setCreatorTime(formattedDate);
            } catch (Exception e) {
                parkingIotExportVO.setCreatorTime("时间格式化出现问题");
            }
            return parkingIotExportVO;

        }).collect(Collectors.toList());
        try {
            publicExportUtil.exportReport(ExportType.PARKING_LOT_EXPORT, collect, httpServletResponse);
        } catch (Exception e) {

        }
    }

    @Override
    public ApiResult appQueryParkingIotService(AppQueryParkingIotRequest appQueryParkingIotRequest) {

        QueryWrapper<BusParkingIot> queryWrapper=crateAppQueryWrapper(appQueryParkingIotRequest);

        List<BusParkingIot> busParkingIotList = busParkingIotMapper.selectList(queryWrapper);

        List<AppParkingIotResponse> collect = busParkingIotList.stream().map(item -> {
            AppParkingIotResponse appParkingIotResponse = new AppParkingIotResponse();
            BeanUtil.copyProperties(item, appParkingIotResponse);
            if(StringUtils.hasText(item.getLatitude())&&StringUtils.hasText(item.getLongitude())){
                //根据经纬计算距离
                Point member1 = new Point(
                        Double.parseDouble(item.getLongitude()),
                        Double.parseDouble(item.getLatitude()));
                Point member = new Point(
                        36.674407,
                        117.132257);
                double distance = DistanceUtil.haversineDistance(member1, member);
                appParkingIotResponse.setDistance(distance);
            }
            return appParkingIotResponse;
        }).collect(Collectors.toList());
        return ApiResult.ok(collect);
    }

    @Override
    public ApiResult appParkingIotDetailsService(Long id) {

        BusParkingIot busParkingIot = busParkingIotMapper.selectById(id);
        if(Objects.isNull(busParkingIot)||
                !busParkingIot.getApprovalStatus().equals(ParkingIotApprovalState.APPROVED.getCode())){

            return ApiResult.fail("数据不存在");
        }

        AppParkingIotResponse appParkingIotResponse = new AppParkingIotResponse();
        BeanUtil.copyProperties(busParkingIot, appParkingIotResponse);
        //根据经纬计算距离
        Point member1 = new Point(
                Double.parseDouble(busParkingIot.getLongitude()),
                Double.parseDouble(busParkingIot.getLatitude()));
        Point member = new Point(
                36.674407,
                117.132257);
        double distance = DistanceUtil.haversineDistance(member1, member);
        appParkingIotResponse.setDistance(distance);
        return ApiResult.ok(appParkingIotResponse);
    }

    public QueryWrapper<BusParkingIot> crateAppQueryWrapper(AppQueryParkingIotRequest request){
        QueryWrapper<BusParkingIot> queryWrapper = new QueryWrapper<>();
        if (StringUtils.hasText(request.getName())) {
            queryWrapper.like("name", request.getName());
        }
        queryWrapper.eq("approval_status",ParkingIotApprovalState.APPROVED.getCode());
        queryWrapper.orderByDesc("creator_time");
        return  queryWrapper;
    }

    public QueryWrapper<BusParkingIot> createQueryWrapper(QueryParkingIotRequest request) {
        QueryWrapper<BusParkingIot> queryWrapper = new QueryWrapper<>();
        //车场名称
        if (StringUtils.hasText(request.getName())) {
            queryWrapper.like("name", request.getName());
        }
        //联系方式
        if (StringUtils.hasText(request.getContactPhone())) {
            queryWrapper.eq("contact_phone", request.getContactPhone());
        }
        //硬件厂商
        if (StringUtils.hasText(request.getHardwareVendor())) {
            queryWrapper.eq("hardware_vendor", request.getHardwareVendor());
        }
        //审核状态
        if (Objects.nonNull(request.getApprovalState())) {
            queryWrapper.eq("approval_status", request.getApprovalState().getCode());
        }

        //时间查询
        if (StringUtils.hasText(request.getStartData()) && StringUtils.hasText(request.getEndData())) {
            Long start = DateConvertUtil.convertQueryStartToMillis(request.getStartData());
            Long end = DateConvertUtil.convertQueryEndToMillis(request.getEndData());
            if (Objects.nonNull(request.getStartData()) && Objects.nonNull(request.getEndData())) {
                queryWrapper.between("creator_time", start, end);
            }

        }
        AdminType roleType = AuthUserMangerContext.getAuthUserEntity().getRoleType();
        if (roleType.equals(AdminType.ADMIN)) {
            //管理员需要判断是否为自己车场
            queryWrapper.eq("super_user_id", AuthUserMangerContext.getUserId());
        }
        queryWrapper.orderByDesc("creator_time");
        return queryWrapper;

    }
}
